home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 31
/
Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso
/
Aminet
/
dev
/
c
/
vbccppcsrc.lha
/
vbcc
/
pasm
/
output_elf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-07
|
15KB
|
461 lines
/* $VER: pasm output_elf.c V1.2 (24.10.98)
*
* This file is part of pasm, a portable PowerPC assembler.
* Copyright (c) 1997-98 Frank Wille
*
* pasm is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
* pasm may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v1.2 (24.10.98) phx
* An empty section with reloc symbols will no longer be deleted.
* v1.1d (27.09.97) phx
* fopen() uses binary mode "b" for windoze/msdog compatibility.
* v1.0 (15.04.98) phx
* The symbol's type was wrong. It was 'Object' for absolute symbols
* and 'Function' for reloc symbols.
* Allocated 1 byte too less, for ".rela.xxx" strings.
* v0.9 (03.04.98) phx
* Reloc section header was corrupted on little endian machines.
* WEAK symbols were generated, instead of GLOBAL ones!
* v0.5 (12.10.97) phx
* Removed "pasm V0.x" from .comment section.
* v0.3 (10.04.97) phx
* Fixed enforcer-hit, when external references are present.
* Some vbcc-specific changes.
* Support for little endian architectures.
* v0.2 (25.03.97) phx
* Writes ELF object for 32-bit PowerPC big-endian. Either absolute
* or ELF output format may be selected. ELF is default for all
* currently supported platforms. PPCasm supports nine different
* relocation types (there are much more...).
* Compiles and works also under NetBSD/amiga (68k).
* Changed function declaration to 'new style' in all sources
* (to avoid problems with '...' for example).
* File created.
*/
#define OUTPUT_ELF_C
#include "ppcasm.h"
#include "elf.h"
#include <time.h>
struct StrTabList {
struct list l;
uint32 index;
};
struct StrTabNode {
struct node n;
char *str;
};
struct ShdrNode {
struct node n;
struct Elf32_Shdr s;
};
struct SymbolNode {
struct node n;
char *name;
struct Elf32_Sym s;
};
struct RelaNode {
struct node n;
struct Elf32_Rela r;
};
static struct Elf32_Ehdr elf_header = {
{ 0x7f,'E','L','F',ELFCLASS32,0,EV_CURRENT,0,0,0,0,0,0,0,0,0 },
ECH(ET_REL),ECH(EM_POWERPC),ECW(EV_CURRENT),0,0,0,0,
ECH(sizeof(struct Elf32_Ehdr)),
0,0,ECH(sizeof(struct Elf32_Shdr)),0,0
};
static char *output_name;
void output_elf32msb(struct GlobalVars *);
static struct ShdrNode *addShdr(struct list *);
static struct SymbolNode *addSymbol(struct list *,struct StrTabList *,char *);
static uint32 addString(struct StrTabList *,char *);
static void addRela(struct list *,uint32,uint32,uint32);
static void fw(FILE *,void *,size_t);
void output_elf32msb(struct GlobalVars *gv)
{
struct list shdrlist,symlist,relalist;
struct StrTabList shstrlist,strlist;
struct ShdrNode *shn;
struct SymbolNode *sym;
uint32 symtabidx,strtabidx,shstrtabidx,firstglobal,align1,align2;
uint32 roffset=0,soffset=sizeof(struct Elf32_Ehdr);
uint32 shdrindex=0,symindex=0;
struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
struct Symbol *symchain;
int i;
FILE *fp;
/* init */
output_name = gv->dest_name;
elf_header.e_ident[EI_DATA] = ELFDATA2MSB;
initlist(&shdrlist);
initlist(&symlist);
initlist(&relalist);
shstrlist.index = strlist.index = 0;
initlist(&shstrlist.l);
initlist(&strlist.l);
addString(&shstrlist,""); /* first string is always "" */
symtabidx = addString(&shstrlist,".symtab");
strtabidx = addString(&shstrlist,".strtab");
shstrtabidx = addString(&shstrlist,".shstrtab");
addShdr(&shdrlist); /* first Shdr is always zero */
addString(&strlist,"");
addSymbol(&symlist,NULL,NULL); /* first symbol table entry always empty */
/* source file name symbol */
if (gv->file) {
++symindex;
sym = addSymbol(&symlist,&strlist,gv->file);
sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_FILE);
sym->s.st_shndx = ECH(SHN_ABS);
}
/* generate section headers for program sections */
while (nextsec = (struct Section *)sec->n.next) {
if (!(sec->flags & SF_DISCARD) &&
(sec->size > 0 || (sec->flags & SF_HASSYMS))) {
sec->index = ++shdrindex;
shn = addShdr(&shdrlist);
shn->s.sh_name = ECVW(addString(&shstrlist,sec->name));
if (sec->type==ST_UDATA || (sec->flags&SF_UNINITIALIZED))
shn->s.sh_type = ECW(SHT_NOBITS);
else
shn->s.sh_type = ECW(SHT_PROGBITS);
shn->s.sh_flags = ECW(SHF_ALLOC);
if (sec->protection & SP_WRITE)
shn->s.sh_flags |= ECW(SHF_WRITE);
if (sec->protection & SP_EXEC)
shn->s.sh_flags |= ECW(SHF_EXECINSTR);
shn->s.sh_offset = ECVW(soffset);
shn->s.sh_size = ECVW(sec->size);
if (shn->s.sh_type == ECW(SHT_PROGBITS))
soffset += sec->size;
shn->s.sh_addralign = ECVW(1<<(uint32)sec->alignment);
/* add section symbol */
sym = addSymbol(&symlist,NULL,NULL);
sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_SECTION);
sym->s.st_shndx = ECVH((uint16)shdrindex);
++symindex;
}
sec = nextsec;
}
/* comment section */
if (gv->ident || gv->vc) {
++shdrindex;
shn = addShdr(&shdrlist);
shn->s.sh_name = ECVW(addString(&shstrlist,".comment"));
shn->s.sh_type = ECW(SHT_PROGBITS);
shn->s.sh_offset = ECVW(soffset);
shn->s.sh_size = 1; /* zero-byte */
if (gv->ident)
shn->s.sh_size += (uint32)strlen(gv->ident)+1;
if (gv->vc)
shn->s.sh_size += 12;
soffset += shn->s.sh_size;
#ifdef LITTLEENDIAN
shn->s.sh_size = l2bw(shn->s.sh_size);
#endif
shn->s.sh_addralign = ECW(1);
/* add section symbol */
sym = addSymbol(&symlist,NULL,NULL);
sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_SECTION);
sym->s.st_shndx = ECVH((uint16)shdrindex);
++symindex;
}
/* build symbol table */
for (i=0; i<SYMHTABSIZE; i++) { /* first, symbols with local binding */
symchain = gv->symbols[i];
while (symchain) {
if (*(symchain->name) != '.') { /* '.symbols' are ignored */
if (symchain->type==SYM_ABS || symchain->type==SYM_RELOC) {
if (symchain->bind == SYMB_LOCAL) {
++symindex;
sym = addSymbol(&symlist,&strlist,symchain->name);
sym->s.st_value = ECVW(symchain->value);
sym->s.st_size = ECVW(symchain->size);
sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,symchain->info);
if (symchain->type == SYM_ABS)
sym->s.st_shndx = ECH(SHN_ABS);
else
sym->s.st_shndx = ECVH((uint16)symchain->relsect->index);
}
}
}
symchain = symchain->hash_chain;
}
}
firstglobal = symindex + 1;
for (i=0; i<SYMHTABSIZE; i++) { /* then, global and weak symbols */
symchain = gv->symbols[i];
while (symchain) {
if (*(symchain->name) != '.') { /* '.symbols' are ignored */
if (symchain->type==SYM_ABS || symchain->type==SYM_RELOC) {
if (symchain->bind > SYMB_LOCAL) {
++symindex;
sym = addSymbol(&symlist,&strlist,symchain->name);
sym->s.st_value = ECVW(symchain->value);
sym->s.st_size = ECVW(symchain->size);
sym->s.st_info = ELF32_ST_INFO(symchain->bind-SYMB_LOCAL,
symchain->info);
if (symchain->type == SYM_ABS)
sym->s.st_shndx = ECH(SHN_ABS);
else
sym->s.st_shndx = ECVH((uint16)symchain->relsect->index);
}
}
}
symchain = symchain->hash_chain;
}
}
/* ".rela.xxx" relocation sections */
sec = (struct Section *)gv->sectionlist.first;
while (nextsec = (struct Section *)sec->n.next) {
if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
struct XReference *nextxref;
struct XReference *xref=(struct XReference *)sec->xreflist.first;
uin